home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / HENSA / MISC / SHELL.ARC / Shell / Sources / c / TextRect < prev    next >
Text File  |  1994-08-29  |  10KB  |  412 lines

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4.  
  5. #include "DeskLib:WimpSWIs.h"
  6. #include "DeskLib:Error.h"
  7.  
  8. #include "Shell.Shell.h"
  9. #include "Shell.Extra.h"
  10. #include "Shell.SafeAlloc.h"
  11. #include "Shell.TextRect.h"
  12.  
  13.  
  14.  
  15. #define Shell_TEXT_INCREMENT 4096
  16.     /* Text is stored in a malloc-ed block which is a multiple of this size    */
  17.     /* so as to avoid repeadly realloc-ing                    */
  18.  
  19.  
  20.  
  21. typedef struct    {            /* this is used to record a reference point in some     */
  22.     int line;            /* text. 'offset' is the position in text of the first     */
  23.     int offset;            /* chr of line-number 'line'.                */
  24.     }
  25.     Shell_textref;
  26.  
  27.  
  28. typedef struct    {
  29.     char        *text;            /* The text.                    */
  30.     int        datasize,        /* Length of text *excluding* the '\0'.        */
  31.             maxdatasize;        /* Space currently rserved for text (excl '\0').*/
  32.     int        numlines,        /* The number of lines in the text...        */
  33.             maxlinelen;        /* Used to check whether window is wide enough.    */
  34.     Shell_textref    top, bottom, last;    /* 'top' is for top visible line in the window.    */
  35.     }                    /* 'bottom' is for the last visible line.    */
  36.     Shell_textrectblock;            /* 'last' is for the last line in the text.    */
  37.                         /* 'top' and 'bottom' are updated each time any    */
  38.                         /* part of the text is re-drawn, and are set to    */
  39.                         /* first and last line of the redrawn text.    */
  40.  
  41.  
  42.  
  43.  
  44.  
  45. static int Shell_TextRectFindLineNumber( const Shell_textrectblock *info, int line)
  46.     /* This function returns the position of the first charater of line number 'line'    */
  47.     /* in info->text. It finds which reference point is nearest to line number 'line,     */
  48.     /* then counts forward or backwards, counting line-feeds until is reaches the start of     */
  49.     /* line-number 'line'.                                    */
  50.     /* It all looks a bit long-winded, partly 'cos I've tried to make it run fast.        */
  51.     /* It should really be in assembler for speed, but I don't know nearly enough for that.    */
  52. {
  53.     Shell_textref    nearest;
  54.     int        step;
  55.  
  56. if ( line >= info->numlines) return -1;
  57. if ( line == 0) return 0;
  58.  
  59. /* find reference line that is closest to line */
  60.  
  61. if ( line <= info->top.line)    {
  62.     if ( (line-info->top.line-line) < line-0 )    {
  63.         nearest = info->top;
  64.         step = -1;
  65.         }
  66.     else    {
  67.         nearest.line=0;
  68.         nearest.offset =0;
  69.         step = +1;
  70.         }
  71.     }
  72.  
  73. else if ( line <= info->bottom.line)    {
  74.     if ((info->bottom.line-line) < (line-info->top.line))    {
  75.         nearest = info->bottom;
  76.         step = -1;
  77.         }
  78.     else    {
  79.         nearest = info->top;
  80.         step = +1;
  81.         }
  82.     }
  83.  
  84. else    {
  85.     if ((info->last.line-line) < (line-info->bottom.line))    {
  86.         nearest = info->last;
  87.         step = -1;
  88.         }
  89.     else    {
  90.         nearest = info->bottom;
  91.         step = +1;
  92.         }
  93.     }
  94.  
  95.  
  96. /*    now step along from the reference line, counting LF's until we have reached the line...    */
  97.  
  98. if ( step > 0)    {
  99.     for ( ; nearest.line != line; nearest.offset++)    {
  100.         if ( info->text[nearest.offset]=='\n')    nearest.line++;
  101.         }
  102.     }
  103. else    {
  104.     for ( nearest.offset -= 2; nearest.line != line; nearest.offset--)    {
  105.         if ( info->text[nearest.offset]=='\n')    nearest.line--;
  106.         }
  107.     nearest.offset+=2;
  108.     }
  109.  
  110.  
  111. /*    nearest.offset is position in info->text of the first chr of line-number 'line'.*/
  112. /*    Just check here that this position is not outside the range of the text, to      */
  113. /*    prevent subsequent overwriting of memory.                    */
  114.  
  115. if ( nearest.offset < 0 || nearest.offset > info->datasize)
  116.     Error_ReportFatal( 1, Error_PLACE "Error in Shell_TextRectFindLineNumber");
  117.  
  118. return nearest.offset;
  119. }
  120.  
  121.  
  122.  
  123.  
  124.  
  125.  
  126. static BOOL Shell_TextRectSaver( char *filename, Shell_rectblock *r)
  127. {
  128. FILE    *f;
  129. Shell_textrectblock *textrectblock = (Shell_textrectblock *) r->reference;
  130.  
  131. f = fopen( filename, "w");
  132. if ( !f) return FALSE;
  133.  
  134. fprintf( f, textrectblock->text);
  135. fclose(f);
  136.  
  137. return TRUE;
  138. }
  139.  
  140.  
  141.  
  142.  
  143.  
  144. #define Min( a, b) ( (a) < (b) ) ? (a) : (b)
  145.  
  146. static int Shell_TextRectRAMSaver(
  147.     task_handle    sourcetask,
  148.     Shell_rectblock    *r,
  149.     task_handle    desttask,
  150.     void        *destbuffer,
  151.     unsigned int    buffersize,
  152.     int        progress
  153.     )
  154. {
  155. Shell_textrectblock    *textrectblock = (Shell_textrectblock *) r->reference;
  156. int n;
  157.  
  158. n = Min( textrectblock->datasize - progress, buffersize);
  159.     /* The length of the text in the rect is ...->datasize. This excludes    */
  160.     /* the '\0', which looks a bit funny if included into a text editor    */
  161.  
  162. Wimp_TransferBlock(
  163.     sourcetask,    textrectblock->text + progress,
  164.     desttask,    destbuffer,
  165.     n
  166.     );
  167. return n;
  168. }
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181. static void Shell_TextRectRedrawer(
  182.     Shell_convertpoint    convert,
  183.     wimp_point        rectsize,
  184.     void            *reference,
  185.     const wimp_rect        *redrawrect
  186.     )
  187.  
  188. {    Shell_textrectblock    *info    = reference;
  189.     wimp_rect        rect    = *redrawrect;
  190.     int            n;
  191.     char            *c;
  192.  
  193. Shell_ConvertToSubTextRect2( &rect, rectsize);
  194.  
  195. n = Shell_TextRectFindLineNumber( info, rect.min.y);
  196.  
  197. if ( n!= -1)    {
  198.     c = &info->text[n];
  199.     info->top.line = rect.min.y;    /* Update top reference point.            */
  200.     info->top.offset  = n;        /* This will be useful in subsequent redraws    */
  201.     if ( rect.max.y > info->numlines) rect.max.y = info->numlines;
  202.         {    int    y;
  203.             char    *cc;
  204.         for ( y=rect.min.y, cc=c; y<=rect.max.y; y++, c=cc+1)    {
  205.             /* print line number y. Put a '\0' temporarily at end of line */
  206.             cc = strchr( c, '\n'); if (cc) *cc=0;
  207.             Shell_PrintString(
  208.                 c, 0, rectsize.y - y*Shell_TEXTYSIZE, convert
  209.                 );
  210.             if (cc)    *cc = '\n';
  211.             else    break;
  212.             }
  213.         info->bottom.line = y;
  214.         info->bottom.offset = ( c - info->text);
  215.         }
  216.     }
  217. return;
  218. }
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226. Shell_rectblock    *Shell_AddTextRect( Shell_windblock *w, int x, int y, int forecol, int backcol)
  227. {
  228.     Shell_textrectblock    *info = Shell_SafeMalloc( sizeof( Shell_textrectblock));
  229.     Shell_rectblock        *r;
  230.  
  231. info->text        = Shell_SafeMalloc( 1+Shell_TEXT_INCREMENT); info->text[0] = 0;
  232. info->maxdatasize    = Shell_TEXT_INCREMENT;
  233. info->datasize        = 0;
  234. info->maxlinelen    = 0;
  235. info->numlines        = 1;
  236. info->last.line        = 0;
  237. info->top.line        = 0;
  238. info->bottom.line    = 0;
  239. info->last.offset    = 0;
  240. info->top.offset     = 0;
  241. info->bottom.offset    = 0;
  242.  
  243. r = Shell_AddRectangle2(
  244.     w, x, y-Shell_TEXTYSIZE, x+Shell_TEXTXSIZE, y,
  245.     Shell_TextRectRedrawer, info
  246.     );
  247.  
  248. Shell_MakeRectIcon( r, forecol, backcol, "R2");
  249.  
  250. r->saver    = Shell_TextRectSaver;
  251. r->ramsaver    = Shell_TextRectRAMSaver;
  252. r->size        = 0;
  253.  
  254. return r;
  255. }
  256.  
  257.  
  258.  
  259.  
  260.  
  261.  
  262.  
  263. Shell_rectblock    *Shell_defaulttextrectblock    = NULL;    /* Not opened yet.    */
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270. void Shell_TextRectPrint( Shell_rectblock *rect, const char *text)
  271. {    int extraneeded;
  272.     int lastLF, numlines, size;
  273.     Shell_textrectblock *info;
  274.  
  275.  
  276. /*    Check whether the rect is Shell_'s default textrect        */
  277. /*    and open a window + textrect if one isn't opened already    */
  278.  
  279. if ( rect == Shell_defaulttextrect)    rect = Shell_defaulttextrectblock;
  280.     /* Plot to the default text-rect window.    */
  281.  
  282. if ( rect == NULL)    {
  283.     rect = Shell_defaulttextrectblock =
  284.         Shell_AddTextRect(
  285.             Shell_OpenGFXWindow(),
  286.             0,
  287.             0,
  288.             colour_BLACK,
  289.             colour_TRANSPARENT
  290.             );
  291.     }
  292.     /* Have to open a new window, and add a textrect    */
  293.  
  294.  
  295. if ( text[0]==0)    return;
  296.  
  297. /* Can now do the actual text-printing...                */
  298. /* This involves adding 'text' to the end of the existing text.        */
  299. /* We have to calculate how many lines are added, whether the         */
  300. /* max-linelength has increased, etc.                    */
  301.  
  302. info = (Shell_textrectblock *) rect->reference;
  303.  
  304. /*    Count number of linefeeds in the new text, also find length, and    */
  305. /*    max line-length. Could do this with str* functions, but this will be    */
  306. /*    quicker as it only loops through the text once.                */
  307.  
  308.     {
  309.     char        *c    = (char *) text;
  310.     int        linelen;
  311.  
  312.     size        =    0;
  313.     numlines    =    0;
  314.  
  315.     lastLF = -(int) ( info->datasize - info->last.offset) - 1;
  316.         /* last.offset is ptr to chr *after* the last '\n', so this makes lastLF    */
  317.         /* be the position of the last '\n'                        */
  318.  
  319.     for ( ; ; c++, size++)    {
  320.         if ( *c == '\n' || ( !*c) )    {
  321.             linelen = (int) ( c-text) - lastLF - 1;
  322.             if ( linelen > info->maxlinelen) info->maxlinelen = linelen;
  323.             if ( *c)    {
  324.                 lastLF = c-text;
  325.                 numlines++;
  326.                 }
  327.             }
  328.         if (!*c) break;
  329.         }
  330.     }
  331.  
  332.  
  333. extraneeded = info->datasize + size - info->maxdatasize;
  334.  
  335. if ( extraneeded > Shell_TEXT_INCREMENT)    {
  336.     info->text = Shell_SafeRealloc( info->text, info->datasize+size+1);
  337.     info->maxdatasize = info->datasize + size;
  338.     }
  339. else if ( extraneeded > 0)    {
  340.     info->text = Shell_SafeRealloc( info->text, info->maxdatasize+Shell_TEXT_INCREMENT+1);
  341.     info->maxdatasize += Shell_TEXT_INCREMENT;
  342.     }
  343.  
  344. strcpy( &info->text[ info->datasize], text);
  345.  
  346. if ( lastLF>=0)    {
  347.     info->last.offset = lastLF + info->datasize+1;    /* datasize is still old value */
  348.                             /* ptr is to the chr AFTER the LF */
  349.     info->last.line += numlines;
  350.     info->numlines  += numlines;
  351.     }
  352.  
  353. info->datasize += size;
  354. rect->size = info->datasize;
  355.  
  356.     {
  357.         int    oldrectminy = rect->rect.min.y;
  358.         BOOL    yscrollbottom = Shell_CheckYScrollIsBottom( rect->window);
  359.         wimp_rect    newrect;    /* This is the new rect at the bottom.    */
  360.  
  361.     rect->rect.max.x = rect->rect.min.x + Shell_TEXTXSIZE * info->maxlinelen;
  362.     rect->rect.min.y = rect->rect.max.y - Shell_TEXTYSIZE * info->numlines;
  363.  
  364.     Shell_ResizeIconRect( rect);
  365.  
  366.     newrect = rect->rect;
  367.     newrect.max.y = oldrectminy + Shell_TEXTYSIZE;
  368.  
  369.     /*Shell_CheckWindSizeAndRedraw( rect->window, &rect->icon.workarearect);*/
  370.     Shell_CheckWindSizeAndRedraw( rect->window, &newrect);
  371.  
  372.     if ( yscrollbottom)    Shell_MoveYScrollToBottom( rect->window);
  373.     }
  374. }
  375.  
  376.  
  377.  
  378.  
  379.  
  380. void    Shell_TextRectPrintf( Shell_rectblock *rectblock, const char *fmt, ...)
  381. {    va_list args;
  382.     int    len;
  383.  
  384. len = strlen( fmt);
  385. if ( len > Shell_stringMAX)    {
  386.     Error_Report( 0,
  387.         "Format string length %i is too long for Shell_TextRectPrintf. Max length is %i",
  388.         len, Shell_stringMAX
  389.         );
  390.     Shell_TextRectPrint( rectblock, "*** string too long for Shell_TextRectPrintf ***\n");
  391.     return;
  392.     }
  393.  
  394. va_start( args, fmt);
  395. vsprintf( Shell_string, fmt, args);
  396. va_end( args);
  397.  
  398. len = strlen( Shell_string);
  399. if ( len > Shell_stringMAX)    {
  400.     Error_Report( 0,
  401.         "Expanded string length %i is too long (max is %i). Shell must exit.",
  402.         len, Shell_stringMAX
  403.         );
  404.     exit( 1);
  405.     }
  406.  
  407. Shell_TextRectPrint( rectblock, Shell_string);
  408. }
  409.  
  410.  
  411.  
  412.